using System;
using System.Collections.Generic;
using Gj.Galaxy.Logic;
using Unity.Entities;
using UnityEngine;

namespace Gj
{
    public class ObjectService : GameService
    {
        public static ObjectService single;

        // private static GameObjectConversionSettings settings;

        private static string[] tmpKey = { "Base", "Plugins", "Skins", "Effects", "Terrains" };

        private static Dictionary<string, Dictionary<string, GameObject>> tmp = new();

        public GameObject container;
        public string prefix;

        static ObjectService()
        {
            single = new ObjectService();
        }

        public static EntityManager EntityManager =>
            // if (_entityManager == null)
            // {
            //     if (World.DefaultGameObjectInjectionWorld != null)
            //     {
            //         _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
            //     }
            // }
            World.DefaultGameObjectInjectionWorld.EntityManager;

        public static bool IsInWorld => World.DefaultGameObjectInjectionWorld != null;

        public void OnDestroy()
        {
            single = new ObjectService();
        }

        public void OnInit()
        {
            single = new ObjectService();
        }

        public void OnUpdate()
        {
            
        }

        // public static Entity ConverEntity(GameObject obj)
        // {
        //     if (settings == null) settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, null);
        //     return GameObjectConversionUtility.ConvertGameObjectHierarchy(obj, settings); 
        // }

        public static T GetObject<T>(uint ID) where T : CoreObject
        {
            var esse = SyncService.Get(ID);
            if (esse == null) return default;
            var obj = esse.GetSyncObject();
            try
            {
                var t = (T)obj;
                return t;
            }
            catch (Exception e)
            {
                return default;
            }
        }

        public ObjectService SetContainer(GameObject obj)
        {
            container = obj;
            return this;
        }

        private GameObject GetTmpObj(string type, string name)
        {
            // Debug.LogErrorFormat("{0}{1}/{2}", prefix, type, name);
            return Resource.LoadAsset<GameObject>(string.Format("{0}{1}/{2}", prefix, type, name));
        }

        private string GetCacheKey(string type, string name)
        {
            return string.Format("{0}-{1}", type, name);
        }

        public GameObject GetObj(string type, string name)
        {
            var key = GetCacheKey(type, name);
            var obj = CacheService.single.GetCache(key);
            if (obj != null) return obj;
            obj = GetTmpObj(type, name);
            if (obj != null)
            {
                obj = ModelTools.Create(obj);
                obj.name = key;
            }
            // else
            // {
            //     Debug.LogErrorFormat("GetObj miss: {0}", key);
            // }

            return obj;
        }

        public T MakeBase<T>(string baseName) where T : Component
        {
            var b = GetObj("Base", baseName);
            if (b != null) return b.GetComponent<T>();
            return null;
        }

        public T MakePlugin<T>(string pluginName, GameObject target = null) where T : Component
        {
            var plugin = GetObj("Plugins", pluginName);
            if (plugin != null)
            {
                plugin.transform.SetParent(target != null ? target.transform : container.transform, false);
                plugin.transform.localPosition = Vector3.zero;
                plugin.transform.localRotation = Quaternion.identity;
                return plugin.GetComponent<T>();
            }

            return null;
        }

        public GameObject MakeSkin(string skinName, GameObject target = null)
        {
            var skin = GetObj("Skins", skinName);
            if (skin != null)
            {
                skin.transform.SetParent(target != null ? target.transform : container.transform, false);
                skin.transform.localPosition = Vector3.zero;
                skin.transform.localRotation = Quaternion.identity;
                return skin;
            }

            return null;
        }

        public GameObject MakeEffect(string effectName, GameObject target = null)
        {
            var effect = GetObj("Effects", effectName);
            if (effect != null)
            {
                effect.transform.SetParent(target != null ? target.transform : container.transform, false);
                effect.transform.localPosition = Vector3.zero;
                effect.transform.localRotation = Quaternion.identity;
                return effect;
            }

            return null;
        }

        public GameObject MakeEffect(string effectName, Vector3 position, Quaternion rotation)
        {
            var effect = GetObj("Effects", effectName);
            if (effect != null)
            {
                effect.transform.SetParent(container.transform, false);
                effect.transform.position = position;
                effect.transform.rotation = rotation;
                return effect;
            }

            return null;
        }

        public GameObject MakeControl(string controlName)
        {
            var control = GetObj("Controls", controlName);
            if (control != null)
            {
                control.transform.SetParent(container.transform, false);
                return control;
            }

            return null;
        }

        public GameObject MakeElement(string elementName)
        {
            var element = GetObj("Elements", elementName);
            if (element != null)
            {
                element.transform.SetParent(container.transform, false);
                return element;
            }

            return null;
        }

        public GameObject MakeCover(string coverName)
        {
            var unit = GetObj("Covers", coverName);
            if (unit != null)
            {
                unit.transform.SetParent(container.transform, false);
                return unit;
            }

            return null;
        }

        public GameObject MakeLogic(string logicName)
        {
            var logic = GetObj("Logics", logicName);
            if (logic != null)
            {
                logic.transform.SetParent(container.transform, false);
                return logic;
            }

            return null;
        }

        public GameObject MakeEngine(string engineName)
        {
            var engine = GetObj("Engines", engineName);
            if (engine != null)
            {
                engine.transform.SetParent(container.transform, false);
                return engine;
            }

            return null;
        }

        public T MakeEmpty<T>(string name) where T : Component
        {
            return MakeEmpty<T>(name, Vector3.zero, Quaternion.identity);
        }

        public T MakeEmpty<T>(string name, Vector3 position, Quaternion rotation) where T : Component
        {
            var key = GetCacheKey("Empty", name);
            var target = CacheService.single.GetCache(key);
            if (target == null)
            {
                target = ModelTools.Create(name);
                target.name = key;
            }

            target.transform.SetParent(container.transform, false);
            target.transform.SetPositionAndRotation(position, rotation);
            return UnityTools.GetComponentRequire<T>(target);
        }

        public Component MakeEmpty(Type type, string name)
        {
            return MakeEmpty(type, name, Vector3.zero, Quaternion.identity);
        }

        public Component MakeEmpty(Type type, string name, Vector3 position, Quaternion rotation)
        {
            var key = GetCacheKey("Empty", name);
            var target = CacheService.single.GetCache(key);
            if (target == null)
            {
                target = ModelTools.Create(name);
                target.name = key;
            }

            target.transform.SetParent(container.transform, false);
            target.transform.SetPositionAndRotation(position, rotation);
            return UnityTools.GetComponentRequire(type, target);
        }

        public T MakeObj<T>(GameObject obj, Vector3 position, Quaternion rotation) where T : Component
        {
            var target = ModelTools.Create(obj);

            target.transform.SetParent(container.transform, false);
            target.transform.SetPositionAndRotation(position, rotation);
            return UnityTools.GetComponentRequire<T>(target);
        }

        public void DestroyObj(GameObject obj)
        {
            obj.SetActive(false);
            obj.transform.parent = null;
            CacheObj(obj);
        }

        public void CacheObj(GameObject obj)
        {
            CacheService.single.SetCache(obj.name, obj);
        }
    }
}